package com.cencat.merchant.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cencat.merchant.entity.Merchant;
import com.cencat.merchant.dto.MerchantQueryDTO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * 商户管理Mapper接口
 * 提供商户数据的增删改查、统计分析、信用评估等数据访问功能
 * 
 * @author cencat
 * @version 1.0
 * @since 2025-01-20
 */
@Mapper
public interface MerchantMapper extends BaseMapper<Merchant> {

    /**
     * 分页查询商户列表
     * 
     * @param page 分页参数
     * @param queryDTO 查询条件
     * @return 商户分页数据
     */
    Page<Merchant> selectMerchantPage(Page<Merchant> page, @Param("query") MerchantQueryDTO queryDTO);

    /**
     * 批量更新商户状态
     * 
     * @param ids 商户ID列表
     * @param status 新状态
     * @return 更新记录数
     */
    @Update("<script>" +
            "UPDATE merchant SET status = #{status}, update_time = NOW() " +
            "WHERE id IN " +
            "<foreach collection='ids' item='id' open='(' separator=',' close=')'>" +
            "#{id}" +
            "</foreach>" +
            "</script>")
    int batchUpdateStatus(@Param("ids") List<Long> ids, @Param("status") String status);

    /**
     * 批量更新商户信用等级
     * 
     * @param ids 商户ID列表
     * @param creditLevel 信用等级
     * @return 更新记录数
     */
    @Update("<script>" +
            "UPDATE merchant SET credit_level = #{creditLevel}, update_time = NOW() " +
            "WHERE id IN " +
            "<foreach collection='ids' item='id' open='(' separator=',' close=')'>" +
            "#{id}" +
            "</foreach>" +
            "</script>")
    int batchUpdateCreditLevel(@Param("ids") List<Long> ids, @Param("creditLevel") String creditLevel);

    /**
     * 批量更新商户服务费率
     * 
     * @param ids 商户ID列表
     * @param serviceRate 服务费率
     * @return 更新记录数
     */
    @Update("<script>" +
            "UPDATE merchant SET service_rate = #{serviceRate}, update_time = NOW() " +
            "WHERE id IN " +
            "<foreach collection='ids' item='id' open='(' separator=',' close=')'>" +
            "#{id}" +
            "</foreach>" +
            "</script>")
    int batchUpdateServiceRate(@Param("ids") List<Long> ids, @Param("serviceRate") BigDecimal serviceRate);

    /**
     * 批量更新商户结算周期
     * 
     * @param ids 商户ID列表
     * @param settlementCycle 结算周期
     * @return 更新记录数
     */
    @Update("<script>" +
            "UPDATE merchant SET settlement_cycle = #{settlementCycle}, update_time = NOW() " +
            "WHERE id IN " +
            "<foreach collection='ids' item='id' open='(' separator=',' close=')'>" +
            "#{id}" +
            "</foreach>" +
            "</script>")
    int batchUpdateSettlementCycle(@Param("ids") List<Long> ids, @Param("settlementCycle") Integer settlementCycle);

    /**
     * 根据状态统计商户数量
     * 
     * @param status 商户状态
     * @return 商户数量
     */
    @Select("SELECT COUNT(*) FROM merchant WHERE status = #{status}")
    Long countByStatus(@Param("status") String status);

    /**
     * 根据商户类型统计商户数量
     * 
     * @param merchantType 商户类型
     * @return 商户数量
     */
    @Select("SELECT COUNT(*) FROM merchant WHERE merchant_type = #{merchantType}")
    Long countByMerchantType(@Param("merchantType") String merchantType);

    /**
     * 根据信用等级统计商户数量
     * 
     * @param creditLevel 信用等级
     * @return 商户数量
     */
    @Select("SELECT COUNT(*) FROM merchant WHERE credit_level = #{creditLevel}")
    Long countByCreditLevel(@Param("creditLevel") String creditLevel);

    /**
     * 计算平均信用分数
     * 
     * @return 平均信用分数
     */
    @Select("SELECT AVG(credit_score) FROM merchant WHERE status = 'ACTIVE'")
    BigDecimal calculateAverageCreditScore();

    /**
     * 计算平均服务费率
     * 
     * @return 平均服务费率
     */
    @Select("SELECT AVG(service_rate) FROM merchant WHERE status = 'ACTIVE'")
    BigDecimal calculateAverageServiceRate();

    /**
     * 查询活跃商户列表
     * 
     * @param limit 限制数量
     * @return 活跃商户列表
     */
    @Select("SELECT * FROM merchant WHERE status = 'ACTIVE' ORDER BY update_time DESC LIMIT #{limit}")
    List<Merchant> selectActiveMerchants(@Param("limit") Integer limit);

    /**
     * 查询待审核商户列表
     * 
     * @param limit 限制数量
     * @return 待审核商户列表
     */
    @Select("SELECT * FROM merchant WHERE status = 'PENDING' ORDER BY create_time ASC LIMIT #{limit}")
    List<Merchant> selectPendingMerchants(@Param("limit") Integer limit);

    /**
     * 查询已停用商户列表
     * 
     * @param limit 限制数量
     * @return 已停用商户列表
     */
    @Select("SELECT * FROM merchant WHERE status = 'INACTIVE' ORDER BY update_time DESC LIMIT #{limit}")
    List<Merchant> selectInactiveMerchants(@Param("limit") Integer limit);

    /**
     * 查询高信用商户列表
     * 
     * @param minCreditScore 最小信用分数
     * @param limit 限制数量
     * @return 高信用商户列表
     */
    @Select("SELECT * FROM merchant WHERE credit_score >= #{minCreditScore} AND status = 'ACTIVE' ORDER BY credit_score DESC LIMIT #{limit}")
    List<Merchant> selectHighCreditMerchants(@Param("minCreditScore") Integer minCreditScore, @Param("limit") Integer limit);

    /**
     * 根据商户类型查询商户列表
     * 
     * @param merchantType 商户类型
     * @param status 商户状态
     * @param limit 限制数量
     * @return 商户列表
     */
    @Select("<script>" +
            "SELECT * FROM merchant WHERE merchant_type = #{merchantType} " +
            "<if test='status != null and status != \"\">" +
            "AND status = #{status} " +
            "</if>" +
            "ORDER BY update_time DESC " +
            "<if test='limit != null'>" +
            "LIMIT #{limit}" +
            "</if>" +
            "</script>")
    List<Merchant> selectMerchantsByType(@Param("merchantType") String merchantType, @Param("status") String status, @Param("limit") Integer limit);

    /**
     * 根据信用等级查询商户列表
     * 
     * @param creditLevel 信用等级
     * @param status 商户状态
     * @param limit 限制数量
     * @return 商户列表
     */
    @Select("<script>" +
            "SELECT * FROM merchant WHERE credit_level = #{creditLevel} " +
            "<if test='status != null and status != \"\">" +
            "AND status = #{status} " +
            "</if>" +
            "ORDER BY credit_score DESC " +
            "<if test='limit != null'>" +
            "LIMIT #{limit}" +
            "</if>" +
            "</script>")
    List<Merchant> selectMerchantsByCreditLevel(@Param("creditLevel") String creditLevel, @Param("status") String status, @Param("limit") Integer limit);

    /**
     * 根据地区查询商户列表
     * 
     * @param region 地区
     * @param status 商户状态
     * @param limit 限制数量
     * @return 商户列表
     */
    @Select("<script>" +
            "SELECT * FROM merchant WHERE region LIKE CONCAT('%', #{region}, '%') " +
            "<if test='status != null and status != \"\">" +
            "AND status = #{status} " +
            "</if>" +
            "ORDER BY update_time DESC " +
            "<if test='limit != null'>" +
            "LIMIT #{limit}" +
            "</if>" +
            "</script>")
    List<Merchant> selectMerchantsByRegion(@Param("region") String region, @Param("status") String status, @Param("limit") Integer limit);

    /**
     * 根据注册时间范围查询商户列表
     * 
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param status 商户状态
     * @param limit 限制数量
     * @return 商户列表
     */
    @Select("<script>" +
            "SELECT * FROM merchant WHERE create_time BETWEEN #{startTime} AND #{endTime} " +
            "<if test='status != null and status != \"\">" +
            "AND status = #{status} " +
            "</if>" +
            "ORDER BY create_time DESC " +
            "<if test='limit != null'>" +
            "LIMIT #{limit}" +
            "</if>" +
            "</script>")
    List<Merchant> selectMerchantsByRegistrationTime(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime, @Param("status") String status, @Param("limit") Integer limit);

    /**
     * 智能推荐合作商户
     * 
     * @param merchantType 商户类型
     * @param minCreditScore 最小信用分数
     * @param maxServiceRate 最大服务费率
     * @param region 地区
     * @param businessScope 业务范围
     * @param limit 限制数量
     * @return 推荐商户列表
     */
    @Select("<script>" +
            "SELECT * FROM merchant " +
            "WHERE status = 'ACTIVE' " +
            "<if test='merchantType != null and merchantType != \"\">" +
            "AND merchant_type = #{merchantType} " +
            "</if>" +
            "<if test='minCreditScore != null'>" +
            "AND credit_score >= #{minCreditScore} " +
            "</if>" +
            "<if test='maxServiceRate != null'>" +
            "AND service_rate <= #{maxServiceRate} " +
            "</if>" +
            "<if test='region != null and region != \"\">" +
            "AND region LIKE CONCAT('%', #{region}, '%') " +
            "</if>" +
            "<if test='businessScope != null and businessScope != \"\">" +
            "AND business_scope LIKE CONCAT('%', #{businessScope}, '%') " +
            "</if>" +
            "ORDER BY credit_score DESC, service_rate ASC " +
            "<if test='limit != null'>" +
            "LIMIT #{limit}" +
            "</if>" +
            "</script>")
    List<Merchant> selectRecommendedMerchants(@Param("merchantType") String merchantType, @Param("minCreditScore") Integer minCreditScore, @Param("maxServiceRate") BigDecimal maxServiceRate, @Param("region") String region, @Param("businessScope") String businessScope, @Param("limit") Integer limit);

    /**
     * 检查商户编码是否存在
     * 
     * @param merchantCode 商户编码
     * @param excludeId 排除的商户ID
     * @return 存在数量
     */
    @Select("<script>" +
            "SELECT COUNT(*) FROM merchant WHERE merchant_code = #{merchantCode} " +
            "<if test='excludeId != null'>" +
            "AND id != #{excludeId}" +
            "</if>" +
            "</script>")
    int existsByMerchantCode(@Param("merchantCode") String merchantCode, @Param("excludeId") Long excludeId);

    /**
     * 检查商户名称是否存在
     * 
     * @param merchantName 商户名称
     * @param excludeId 排除的商户ID
     * @return 存在数量
     */
    @Select("<script>" +
            "SELECT COUNT(*) FROM merchant WHERE merchant_name = #{merchantName} " +
            "<if test='excludeId != null'>" +
            "AND id != #{excludeId}" +
            "</if>" +
            "</script>")
    int existsByMerchantName(@Param("merchantName") String merchantName, @Param("excludeId") Long excludeId);

    /**
     * 搜索商户
     * 
     * @param keyword 关键词
     * @param searchType 搜索类型
     * @param limit 限制数量
     * @return 商户列表
     */
    @Select("<script>" +
            "SELECT * FROM merchant WHERE 1=1 " +
            "<choose>" +
            "<when test='searchType == \"code\"'>" +
            "AND merchant_code LIKE CONCAT('%', #{keyword}, '%') " +
            "</when>" +
            "<when test='searchType == \"name\"'>" +
            "AND merchant_name LIKE CONCAT('%', #{keyword}, '%') " +
            "</when>" +
            "<when test='searchType == \"contact\"'>" +
            "AND contact_person LIKE CONCAT('%', #{keyword}, '%') " +
            "</when>" +
            "<when test='searchType == \"phone\"'>" +
            "AND contact_phone LIKE CONCAT('%', #{keyword}, '%') " +
            "</when>" +
            "<otherwise>" +
            "AND (merchant_code LIKE CONCAT('%', #{keyword}, '%') " +
            "OR merchant_name LIKE CONCAT('%', #{keyword}, '%') " +
            "OR contact_person LIKE CONCAT('%', #{keyword}, '%') " +
            "OR contact_phone LIKE CONCAT('%', #{keyword}, '%')) " +
            "</otherwise>" +
            "</choose>" +
            "ORDER BY update_time DESC " +
            "<if test='limit != null'>" +
            "LIMIT #{limit}" +
            "</if>" +
            "</script>")
    List<Merchant> searchMerchants(@Param("keyword") String keyword, @Param("searchType") String searchType, @Param("limit") Integer limit);

    /**
     * 查询商户列表（用于导出）
     * 
     * @param queryDTO 查询条件
     * @return 商户列表
     */
    List<Merchant> selectMerchantList(@Param("query") MerchantQueryDTO queryDTO);

    /**
     * 计算指定时间范围内的商户注册数量
     * 
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param status 商户状态
     * @return 商户数量
     */
    @Select("<script>" +
            "SELECT COUNT(*) FROM merchant " +
            "WHERE create_time BETWEEN #{startTime} AND #{endTime} " +
            "<if test='status != null and status != \"\">" +
            "AND status = #{status}" +
            "</if>" +
            "</script>")
    Integer calculateMerchantCount(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime, @Param("status") String status);

    /**
     * 计算指定时间范围内的平均信用分数
     * 
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 平均信用分数
     */
    @Select("SELECT AVG(credit_score) FROM merchant " +
            "WHERE create_time BETWEEN #{startTime} AND #{endTime} AND status = 'ACTIVE'")
    Double calculateAverageCreditScoreByTime(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);

    /**
     * 获取商户趋势数据
     * 
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param trendType 趋势类型
     * @return 趋势数据
     */
    List<Map<String, Object>> selectMerchantTrends(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime, @Param("trendType") String trendType);

    /**
     * 获取商户排行榜
     * 
     * @param rankType 排行类型
     * @param limit 限制数量
     * @return 排行榜数据
     */
    List<Map<String, Object>> selectMerchantRanking(@Param("rankType") String rankType, @Param("limit") Integer limit);

    /**
     * 获取商户分布数据
     * 
     * @param distributionType 分布类型
     * @return 分布数据
     */
    List<Map<String, Object>> selectMerchantDistribution(@Param("distributionType") String distributionType);

    /**
     * 更新商户信用分数
     * 
     * @param merchantId 商户ID
     * @param creditScore 信用分数
     * @return 更新记录数
     */
    @Update("UPDATE merchant SET credit_score = #{creditScore}, update_time = NOW() WHERE id = #{merchantId}")
    int updateCreditScore(@Param("merchantId") Long merchantId, @Param("creditScore") Integer creditScore);

    /**
     * 更新商户最后登录时间
     * 
     * @param merchantId 商户ID
     * @param lastLoginTime 最后登录时间
     * @return 更新记录数
     */
    @Update("UPDATE merchant SET last_login_time = #{lastLoginTime}, update_time = NOW() WHERE id = #{merchantId}")
    int updateLastLoginTime(@Param("merchantId") Long merchantId, @Param("lastLoginTime") LocalDateTime lastLoginTime);

    /**
     * 批量更新商户信用分数
     * 
     * @param merchantIds 商户ID列表
     * @param creditScore 信用分数
     * @return 更新记录数
     */
    @Update("<script>" +
            "UPDATE merchant SET credit_score = #{creditScore}, update_time = NOW() " +
            "WHERE id IN " +
            "<foreach collection='merchantIds' item='id' open='(' separator=',' close=')'>" +
            "#{id}" +
            "</foreach>" +
            "</script>")
    int batchUpdateCreditScore(@Param("merchantIds") List<Long> merchantIds, @Param("creditScore") Integer creditScore);

    /**
     * 获取商户统计数据
     * 
     * @param merchantId 商户ID
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 统计数据
     */
    Map<String, Object> selectMerchantStats(@Param("merchantId") Long merchantId, @Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);

    /**
     * 获取商户业务统计
     * 
     * @param merchantId 商户ID
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 业务统计数据
     */
    Map<String, Object> selectMerchantBusinessStats(@Param("merchantId") Long merchantId, @Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);

    /**
     * 获取商户财务统计
     * 
     * @param merchantId 商户ID
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 财务统计数据
     */
    Map<String, Object> selectMerchantFinancialStats(@Param("merchantId") Long merchantId, @Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);

    /**
     * 获取地区商户统计
     * 
     * @param region 地区
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 地区商户统计数据
     */
    Map<String, Object> selectRegionMerchantStats(@Param("region") String region, @Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);

    /**
     * 获取商户类型统计
     * 
     * @param merchantType 商户类型
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 商户类型统计数据
     */
    Map<String, Object> selectMerchantTypeStats(@Param("merchantType") String merchantType, @Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);

    /**
     * 根据信用分数范围查询商户列表
     * 
     * @param minScore 最小信用分数
     * @param maxScore 最大信用分数
     * @param status 商户状态
     * @param limit 限制数量
     * @return 商户列表
     */
    @Select("<script>" +
            "SELECT * FROM merchant WHERE credit_score BETWEEN #{minScore} AND #{maxScore} " +
            "<if test='status != null and status != \"\">" +
            "AND status = #{status} " +
            "</if>" +
            "ORDER BY credit_score DESC " +
            "<if test='limit != null'>" +
            "LIMIT #{limit}" +
            "</if>" +
            "</script>")
    List<Merchant> selectMerchantsByCreditScoreRange(@Param("minScore") Integer minScore, @Param("maxScore") Integer maxScore, @Param("status") String status, @Param("limit") Integer limit);

    /**
     * 根据服务费率范围查询商户列表
     * 
     * @param minRate 最小服务费率
     * @param maxRate 最大服务费率
     * @param status 商户状态
     * @param limit 限制数量
     * @return 商户列表
     */
    @Select("<script>" +
            "SELECT * FROM merchant WHERE service_rate BETWEEN #{minRate} AND #{maxRate} " +
            "<if test='status != null and status != \"\">" +
            "AND status = #{status} " +
            "</if>" +
            "ORDER BY service_rate ASC " +
            "<if test='limit != null'>" +
            "LIMIT #{limit}" +
            "</if>" +
            "</script>")
    List<Merchant> selectMerchantsByServiceRateRange(@Param("minRate") BigDecimal minRate, @Param("maxRate") BigDecimal maxRate, @Param("status") String status, @Param("limit") Integer limit);
}